home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / internet / other / ka9q / nhclb120.zoo / lapb.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-18  |  14.4 KB  |  634 lines

  1. /* Link Access Procedures Balanced (LAPB) - with changes for rational
  2.  * behavior over packet radio
  3.  */
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "timer.h"
  7. #include "ax25.h"
  8. #include "lapb.h"
  9. #include "iface.h"
  10. #ifdef    UNIX
  11. #include <memory.h>
  12. #endif
  13. static int ackours();
  14. static int procdata();
  15. /* Process incoming frames */
  16. int
  17. lapb_input(axp,cmdrsp,bp)
  18. struct ax25_cb *axp;        /* Link control structure */
  19. char cmdrsp;            /* Command/response flag */
  20. struct mbuf *bp;        /* Rest of frame, starting with ctl */
  21. {
  22.     int16 ftype();
  23.     void lapbstate();
  24.     char control;
  25.     char class;        /* General class (I/S/U) of frame */
  26.     int16 type;        /* Specific type (I/RR/RNR/etc) of frame */
  27.     char pf;        /* extracted poll/final bit */
  28.     char poll = 0;
  29.     char final = 0;
  30.     int nr;            /* ACK number of incoming frame */
  31.     int ns;            /* Seq number of incoming frame */
  32.     char tmp;
  33.  
  34.     if(bp == NULLBUF || axp == NULLAX25){
  35.         free_p(bp);
  36.         return -1;
  37.     }
  38.  
  39.     /* Extract the various parts of the control field for easy use */
  40.     control = pullchar(&bp);
  41.     type = ftype(control);
  42.     class = type & 0x3;
  43.     pf = control & PF;
  44.     /* Check for polls and finals */
  45.     if(pf){
  46.         switch(cmdrsp){
  47.         case COMMAND:
  48.             poll = YES;
  49.             break;
  50.         case RESPONSE:
  51.             final = YES;
  52.             break;
  53.         }
  54.     }
  55.     /* Extract sequence numbers, if present */
  56.     switch(class){
  57.     case I:
  58.     case I+2:
  59.         ns = (control >> 1) & MMASK;
  60.     case S:    /* Note fall-thru */
  61.         nr = (control >> 5) & MMASK;
  62.         break;
  63.     }
  64.     /* This section follows the SDL diagrams by K3NA fairly closely */
  65.     switch(axp->state){
  66.     case DISCONNECTED:
  67.         switch(type){
  68.         case SABM:    /* Initialize or reset link */
  69.             sendctl(axp,RESPONSE,UA|pf);    /* Always accept */
  70.             clr_ex(axp);
  71.             axp->unack = axp->vr = axp->vs = 0;
  72.             lapbstate(axp,CONNECTED);/* Resets state counters */
  73.             start_timer(&axp->t3);
  74.             break;
  75.         case DM:    /* Ignore to avoid infinite loops */
  76.             break;
  77.         default:    /* All others get DM */
  78.             sendctl(axp,RESPONSE,DM|pf);
  79.             break;
  80.         }
  81.         break;
  82.     case SETUP:
  83.         switch(type){
  84.         case SABM:    /* Simultaneous open */
  85.             sendctl(axp,RESPONSE,UA|pf);
  86.             break;
  87.         case DISC:
  88.             sendctl(axp,RESPONSE,DM|pf);
  89.             break;
  90.         case UA:    /* Connection accepted */
  91.             /* Note: xmit queue not cleared */
  92.             stop_timer(&axp->t1);
  93.             start_timer(&axp->t3);
  94.             axp->unack = axp->vr = axp->vs = 0;
  95.             lapbstate(axp,CONNECTED);
  96.             break;            
  97.         case DM:    /* Connection refused */
  98.             free_q(&axp->txq);
  99.             stop_timer(&axp->t1);
  100.             lapbstate(axp,DISCONNECTED);
  101.             break;
  102.         default:    /* All other frames ignored */
  103.             break;
  104.         }
  105.         break;
  106.     case DISCPENDING:
  107.         switch(type){
  108.         case SABM:
  109.             sendctl(axp,RESPONSE,DM|pf);
  110.             break;
  111.         case DISC:
  112.             sendctl(axp,RESPONSE,UA|pf);
  113.             break;
  114.         case UA:
  115.         case DM:
  116.             stop_timer(&axp->t1);
  117.             lapbstate(axp,DISCONNECTED);
  118.             break;
  119.         default:    /* Respond with DM only to command polls */
  120.             if(poll)
  121.                 sendctl(axp,RESPONSE,DM|pf);
  122.             break;
  123.         }
  124.         break;
  125.     case CONNECTED:
  126.         switch(type){
  127.         case SABM:
  128.             sendctl(axp,RESPONSE,UA|pf);
  129.             clr_ex(axp);
  130.             free_q(&axp->txq);
  131.             stop_timer(&axp->t1);
  132.             start_timer(&axp->t3);
  133.             axp->unack = axp->vr = axp->vs = 0;
  134.             lapbstate(axp,CONNECTED); /* Purge queues */
  135.             break;
  136.         case DISC:
  137.             free_q(&axp->txq);
  138.             sendctl(axp,RESPONSE,UA|pf);
  139.             stop_timer(&axp->t1);
  140.             stop_timer(&axp->t3);
  141.             lapbstate(axp,DISCONNECTED);
  142.             break;
  143. /* This code is cribbed from the NOS version, in order to make a */
  144. /* temporary fix to a pathological looping behavior during connect (dmf) */
  145.         case DM:
  146.             lapbstate(axp,DISCONNECTED);
  147.             break;
  148.         case UA:
  149.             est_link(axp);
  150.             lapbstate(axp,SETUP);    /* Re-establish */    
  151.             break;
  152. /* End of cribbed code (dmf) */            
  153.         case FRMR:
  154.             est_link(axp);
  155.             lapbstate(axp,SETUP);    /* Re-establish link */
  156.             break;
  157.         case RR:
  158.         case RNR:
  159.             axp->remotebusy = (control == RNR) ? YES : NO;
  160.             if(poll)
  161.                 enq_resp(axp);
  162.             (void)ackours(axp,nr);
  163.             break;
  164.         case REJ:
  165.             axp->remotebusy = NO;
  166.             if(poll)
  167.                 enq_resp(axp);
  168.             (void)ackours(axp,nr);
  169.             stop_timer(&axp->t1);
  170.             start_timer(&axp->t3);
  171.             /* This may or may not actually invoke transmission,
  172.              * depending on whether this REJ was caused by
  173.              * our losing his prior ACK.
  174.              */
  175.             inv_rex(axp);
  176.             break;    
  177.         case I:
  178.             (void)ackours(axp,nr); /** == -1) */
  179.             if(len_mbuf(axp->rxq) >= axp->window){
  180.                 /* Too bad he didn't listen to us; he'll
  181.                  * have to resend the frame later. This
  182.                  * drastic action is necessary to avoid
  183.                  * deadlock.
  184.                  */
  185.                 if(poll)
  186.                     sendctl(axp,RESPONSE,RNR|pf);
  187.                 free_p(bp);
  188.                 bp = NULLBUF;
  189.                 break;
  190.             }
  191.             /* Reject or ignore I-frames with receive sequence number errors */
  192.             if(ns != axp->vr){
  193.                 if(axp->proto == V1 || !axp->rejsent){
  194.                     axp->rejsent = YES;
  195.                     sendctl(axp,RESPONSE,REJ | pf);
  196.                 }
  197.                 axp->response = 0;
  198.                 stop_timer(&axp->t2);
  199.                 break;
  200.             }
  201.             axp->rejsent = NO;
  202.             axp->vr = (axp->vr+1) & MMASK;
  203.             tmp = len_mbuf(axp->rxq) >= axp->window ? RNR : RR;
  204.             if(poll){
  205.                 sendctl(axp,RESPONSE,tmp|PF);
  206.             } else {
  207.                 axp->response = tmp;
  208.                 start_timer(&axp->t2);
  209.             }
  210.             procdata(axp,bp);
  211.             bp = NULLBUF;
  212.             break;
  213.         default:    /* All others ignored */
  214.             break;
  215.         }
  216.         break;
  217.     case RECOVERY:
  218.         switch(type){
  219.         case SABM:
  220.             sendctl(axp,RESPONSE,UA|pf);
  221.             clr_ex(axp);
  222.             stop_timer(&axp->t1);
  223.             start_timer(&axp->t3);
  224.             axp->unack = axp->vr = axp->vs = 0;
  225.             lapbstate(axp,CONNECTED); /* Purge queues */
  226.             break;
  227.         case DISC:
  228.             free_q(&axp->txq);
  229.             sendctl(axp,RESPONSE,UA|pf);
  230.             stop_timer(&axp->t1);
  231.             stop_timer(&axp->t3);
  232.             axp->response = UA;
  233.             lapbstate(axp,DISCONNECTED);
  234.             break;
  235. /* This code is cribbed from the NOS version, in order to make a */
  236. /* temporary fix to a pathological looping behavior during connect (dmf) */
  237.         case DM:
  238.             lapbstate(axp,DISCONNECTED);
  239.             break;
  240.         case UA:
  241.             est_link(axp);
  242.             lapbstate(axp,SETUP);    /* Re-establish */    
  243.             break;
  244. /* End of cribbed code (dmf) */            
  245.         case FRMR:
  246.             est_link(axp);
  247.             lapbstate(axp,SETUP);    /* Re-establish link */
  248.             break;
  249.         case RR:
  250.         case RNR:
  251.             axp->remotebusy = (control == RNR) ? YES : NO;
  252.             if(axp->proto == V1 || final){
  253.                 stop_timer(&axp->t1);
  254.                 (void)ackours(axp,nr);
  255.                 if(axp->unack != 0){
  256.                     inv_rex(axp);
  257.                 } else {
  258.                     start_timer(&axp->t3);
  259.                     lapbstate(axp,CONNECTED);
  260.                 }
  261.             } else {
  262.                 if(poll)
  263.                     enq_resp(axp);
  264.                 (void)ackours(axp,nr);
  265.                 /* Keep timer running even if all frames
  266.                  * were acked, since we must see a Final
  267.                  */
  268.                 if(!run_timer(&axp->t1))
  269.                     start_timer(&axp->t1);
  270.             }
  271.             break;
  272.         case REJ:
  273.             axp->remotebusy = NO;
  274.             /* Don't insist on a Final response from the old proto */
  275.             if(axp->proto == V1 || final){
  276.                 stop_timer(&axp->t1);
  277.                 (void)ackours(axp,nr);
  278.                 if(axp->unack != 0){
  279.                     inv_rex(axp);
  280.                 } else {
  281.                     start_timer(&axp->t3);
  282.                     lapbstate(axp,CONNECTED);
  283.                 }
  284.             } else {
  285.                 if(poll)
  286.                     enq_resp(axp);
  287.                 (void)ackours(axp,nr);
  288.                 if(axp->unack != 0){
  289.                     /* This is certain to trigger output */
  290.                     inv_rex(axp);
  291.                 }
  292.                 /* A REJ that acks everything but doesn't
  293.                  * have the F bit set can cause a deadlock.
  294.                  * So make sure the timer is running.
  295.                  */
  296.                 if(!run_timer(&axp->t1))
  297.                     start_timer(&axp->t1);
  298.             }
  299.             break;
  300.         case I:
  301.             (void)ackours(axp,nr); /** == -1) */
  302.             /* Make sure timer is running, since an I frame
  303.              * cannot satisfy a poll
  304.              */
  305.             if(!run_timer(&axp->t1))
  306.                 start_timer(&axp->t1);
  307.             if(len_mbuf(axp->rxq) >= axp->window){
  308.                 /* Too bad he didn't listen to us; he'll
  309.                  * have to resend the frame later. This
  310.                  * drastic action is necessary to avoid
  311.                  * memory deadlock.
  312.                  */
  313.                 sendctl(axp,RESPONSE,RNR | pf);
  314.                 free_p(bp);
  315.                 bp = NULLBUF;
  316.                 break;
  317.             }
  318.             /* Reject or ignore I-frames with receive sequence number errors */
  319.             if(ns != axp->vr){
  320.                 if(axp->proto == V1 || !axp->rejsent){
  321.                     axp->rejsent = YES;
  322.                     sendctl(axp,RESPONSE,REJ | pf);
  323.                 }
  324.                 axp->response = 0;
  325.                 stop_timer(&axp->t2);
  326.                 break;
  327.             }
  328.             axp->rejsent = NO;
  329.             axp->vr = (axp->vr+1) & MMASK;
  330.             tmp = len_mbuf(axp->rxq) >= axp->window ? RNR : RR;
  331.             if(poll){
  332.                 sendctl(axp,RESPONSE,tmp|PF);
  333.             } else {
  334.                 axp->response = tmp;
  335.                 start_timer(&axp->t2);
  336.             }
  337.             procdata(axp,bp);
  338.             bp = NULLBUF;
  339.             break;
  340.         default:
  341.             break;        /* Ignored */
  342.         }
  343.         break;
  344.     case FRAMEREJECT:
  345.         switch(type){
  346.         case SABM:
  347.             sendctl(axp,RESPONSE,UA|pf);
  348.             clr_ex(axp);
  349.             axp->unack = axp->vr = axp->vs = 0;
  350.             stop_timer(&axp->t1);
  351.             start_timer(&axp->t3);
  352.             lapbstate(axp,CONNECTED);
  353.             break;
  354.         case DISC:
  355.             free_q(&axp->txq);
  356.             sendctl(axp,RESPONSE,UA|pf);
  357.             stop_timer(&axp->t1);
  358.             lapbstate(axp,DISCONNECTED);
  359.             break;
  360.         case DM:
  361.             stop_timer(&axp->t1);
  362.             lapbstate(axp,DISCONNECTED);
  363.             break;
  364.         default:
  365.             frmr(axp,0,0);
  366.             break;
  367.         }
  368.         break;
  369.     }
  370.     free_p(bp);    /* In case anything's left */
  371.  
  372.     /* See if we can send some data, perhaps piggybacking an ack.
  373.      * If successful, lapb_output will clear axp->response.
  374.      */
  375.     lapb_output(axp);
  376.  
  377.     /* Empty the trash */
  378.     if(axp->state == DISCONNECTED)
  379.         del_ax25(axp);
  380.     return 0;
  381. }
  382. /* Handle incoming acknowledgements for frames we've sent.
  383.  * Free frames being acknowledged.
  384.  * Return -1 to cause a frame reject if number is bad, 0 otherwise
  385.  */
  386. static int
  387. ackours(axp,n)
  388. struct ax25_cb *axp;
  389. char n;
  390. {    
  391.     struct mbuf *bp;
  392.     int acked = 0;    /* Count of frames acked by this ACK */
  393.     int oldest;    /* Seq number of oldest unacked I-frame */
  394.  
  395.     /* Free up acknowledged frames by purging frames from the I-frame
  396.      * transmit queue. Start at the remote end's last reported V(r)
  397.      * and keep going until we reach the new sequence number.
  398.      * If we try to free a null pointer,
  399.      * then we have a frame reject condition.
  400.      */
  401.     oldest = (axp->vs - axp->unack) & MMASK;
  402.     while(axp->unack != 0 && oldest != n){
  403.         if((bp = dequeue(&axp->txq)) == NULLBUF){
  404.             /* Acking unsent frame */
  405.             return -1;
  406.         }
  407.         free_p(bp);
  408.         axp->unack--;
  409.         acked++;
  410.         axp->retries = 0;
  411.         oldest = (oldest + 1) & MMASK;
  412.     }
  413.     if(axp->unack == 0){
  414.         /* All frames acked, stop timeout */
  415.         stop_timer(&axp->t1);
  416.         start_timer(&axp->t3);
  417.     } else if(acked != 0) { 
  418.         /* Partial ACK; restart timer */
  419.         start_timer(&axp->t1);
  420.     }
  421.     /* If user has set a transmit upcall, indicate how many frames
  422.      * may be queued
  423.      */
  424.     if(acked != 0 && axp->t_upcall != NULLVFP)
  425.         (*axp->t_upcall)(axp,axp->paclen * (axp->maxframe - axp->unack));
  426.  
  427.     return 0;
  428. }
  429.  
  430. /* Establish data link */
  431. est_link(axp)
  432. struct ax25_cb *axp;
  433. {
  434.     clr_ex(axp);
  435.     axp->retries = 0;
  436.     sendctl(axp,COMMAND,SABM|PF);
  437.     stop_timer(&axp->t3);
  438.     start_timer(&axp->t1);
  439. }
  440. /* Clear exception conditions */
  441. clr_ex(axp)
  442. struct ax25_cb *axp;
  443. {
  444.     axp->remotebusy = NO;
  445.     axp->rejsent = NO;
  446.     axp->response = 0;
  447.     stop_timer(&axp->t3);
  448. }
  449. /* Enquiry response */
  450. enq_resp(axp)
  451. struct ax25_cb *axp;
  452. {
  453.     char ctl;
  454.  
  455.     ctl = len_mbuf(axp->rxq) >= axp->window ? RNR|PF : RR|PF;    
  456.     sendctl(axp,RESPONSE,ctl);
  457.     axp->response = 0;
  458.     stop_timer(&axp->t3);
  459. }
  460. /* Invoke retransmission */
  461. inv_rex(axp)
  462. struct ax25_cb *axp;
  463. {
  464.     axp->vs -= axp->unack;
  465.     axp->vs &= MMASK;
  466.     axp->unack = 0;
  467. }
  468. /* Generate Frame Reject (FRMR) response
  469.  * If reason != 0, this is the initial error frame
  470.  * If reason == 0, resend the last error frame
  471.  */
  472. int
  473. frmr(axp,control,reason)
  474. register struct ax25_cb *axp;
  475. char control;
  476. char reason;
  477. {
  478.     struct mbuf *frmrinfo;
  479.     register char *cp;
  480.     void lapbstate();
  481.  
  482.     if(reason != 0){
  483.         cp = axp->frmrinfo;
  484.         *cp++ = control;
  485.         *cp++ =  axp->vr << 5 || axp->vs << 1;
  486.         *cp = reason;
  487.     }
  488.     if((frmrinfo = alloc_mbuf(3)) == NULLBUF)
  489.         return -1;    /* No memory */
  490.     frmrinfo->cnt = 3;
  491.     memcpy(frmrinfo->data,axp->frmrinfo,3);
  492.     return sendframe(axp,RESPONSE,FRMR|(control&PF),frmrinfo);
  493. }
  494.  
  495. /* Send S or U frame to currently connected station */
  496. int
  497. sendctl(axp,cmdrsp,cmd)
  498. struct ax25_cb *axp;
  499. char cmdrsp,cmd;
  500. {
  501.     int16 ftype();
  502.  
  503.     if((ftype(cmd) & 0x3) == S)    /* Insert V(R) if S frame */
  504.         cmd |= (axp->vr << 5);
  505.     return sendframe(axp,cmdrsp,cmd,NULLBUF);
  506. }
  507. /* Start data transmission on link, if possible
  508.  * Return number of frames sent
  509.  */
  510. int
  511. lapb_output(axp)
  512. register struct ax25_cb *axp;
  513. {
  514.     register struct mbuf *bp;
  515.     struct mbuf *tbp;
  516.     char control;
  517.     int sent = 0;
  518.     int i;
  519.  
  520.     if(axp == NULLAX25
  521.      || (axp->state != RECOVERY && axp->state != CONNECTED)
  522.      || axp->remotebusy)
  523.         return 0;
  524.  
  525.     /* Dig into the send queue for the first unsent frame */
  526.     bp = axp->txq;
  527.     for(i = 0; i < axp->unack; i++){
  528.         if(bp == NULLBUF)
  529.             break;    /* Nothing to do */
  530.         bp = bp->anext;
  531.     }
  532.     /* Start at first unsent I-frame, stop when either the
  533.      * number of unacknowledged frames reaches the maxframe limit,
  534.      * or when there are no more frames to send
  535.      */
  536.     while(bp != NULLBUF && axp->unack < axp->maxframe){
  537.         control = I | (axp->vs++ << 1) | (axp->vr << 5);
  538.         axp->vs &= MMASK;
  539.         dup_p(&tbp,bp,0,len_mbuf(bp));
  540.         if(tbp == NULLBUF)
  541.             return sent;    /* Probably out of memory */
  542.         sendframe(axp,COMMAND,control,tbp);
  543.         axp->unack++;
  544.         /* We're implicitly acking any data he's sent, so stop any
  545.          * delayed ack
  546.          */
  547.         axp->response = 0;
  548.         stop_timer(&axp->t2);
  549.         if(!run_timer(&axp->t1)){
  550.             stop_timer(&axp->t3);
  551.             start_timer(&axp->t1);
  552.         }
  553.         sent++;
  554.         bp = bp->anext;
  555.     }
  556.     return sent;
  557. }
  558. /* Set new link state.
  559.  * If the new state is disconnected, also free the link control block.
  560.  */
  561. void
  562. lapbstate(axp,s)
  563. struct ax25_cb *axp;
  564. int s;
  565. {
  566.     int oldstate;
  567.  
  568.     oldstate = axp->state;
  569.     axp->state = s;
  570.     if(s == DISCONNECTED){
  571.         stop_timer(&axp->t1);
  572.         stop_timer(&axp->t2);
  573.         stop_timer(&axp->t3);
  574.         free_q(&axp->txq);
  575.     }
  576.     /* Don't bother the client unless the state is really changing */
  577.     if(oldstate != s && axp->s_upcall != NULLVFP)
  578.         (*axp->s_upcall)(axp,oldstate,s);
  579. }
  580. /* Process a valid incoming I frame */
  581. static
  582. procdata(axp,bp)
  583. struct ax25_cb *axp;
  584. struct mbuf *bp;
  585. {
  586.     char pid;
  587.     int ip_route();
  588.  
  589.     /* Extract level 3 PID */
  590.     if(pullup(&bp,&pid,1) != 1)
  591.         return;    /* No PID */
  592.  
  593.     switch(pid & (PID_FIRST|PID_LAST)){
  594.     case PID_FIRST:
  595.         /* "Shouldn't happen", but flush any accumulated frags */
  596.         free_p(axp->rxasm);
  597.         axp->rxasm = NULLBUF;
  598.     case 0:    /* Note fall-thru */
  599.         /* Beginning or middle of message, just accumulate */
  600.         append(&axp->rxasm,bp);
  601.         return;
  602.     case PID_LAST:
  603.         /* Last frame of multi-frame message; extract it */
  604.         append(&axp->rxasm,bp);
  605.         bp = axp->rxasm;
  606.         axp->rxasm = NULLBUF;
  607.         break;
  608.     case PID_FIRST|PID_LAST:
  609.         /* Do nothing with reassembly queue, allowing single-frame
  610.          * messages to be interspersed with fragments of multi-frame
  611.          * messages
  612.          */
  613.         break;
  614.     }
  615.     /* Last frame in sequence; kick entire message upstairs */
  616.     switch(pid & PID_PID){
  617.     case PID_IP:        /* DoD Internet Protocol */
  618.         ip_route(bp,0);
  619.         break;
  620.     case PID_NO_L3:        /* Enqueue for application */
  621.         append(&axp->rxq,bp);
  622.         if(axp->r_upcall != NULLVFP)
  623.             (*axp->r_upcall)(axp,len_mbuf(axp->rxq));
  624.         break;    
  625.     case PID_NETROM:
  626.         nr_route(bp,axp);
  627.         break;
  628.     default:        /* Note: ARP is invalid here */    
  629.         free_p(bp);
  630.         break;            
  631.     }
  632. }
  633.  
  634.